package com.cdp.web.controller.system.openFeign;

import com.cdp.common.core.domain.AjaxResult;
import com.cdp.common.core.domain.entity.SysMechanicalPerformance;
import com.cdp.common.core.domain.entity.SysSlump;
import com.cdp.common.utils.ExcelUtils;
import com.cdp.common.utils.poi.ExcelUtil;
import com.cdp.system.dto.*;
import com.cdp.system.service.ISysFileAuditService;
import com.cdp.system.service.ISysMechanicalPerformanceService;
import com.cdp.system.service.ISysPklService;
import com.cdp.system.service.ISysSlumpService;
import com.cdp.system.vo.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

@RestController
@RequestMapping("/feign")
@Slf4j
public class FeignController {

    @Autowired
    private FileClient fileClient;

    @Value("${filePython.upload-pkl-excel}")
    private String filePythonPklExcel;  // 读取配置文件中的路径

    @Value("${filePython.upload-pkl-path}")
    private String uploadPklPath;


    @Autowired
    private ISysPklService sysPklService;
    @Autowired
    private ISysFileAuditService fileAuditService;
    @Autowired
    private ISysMechanicalPerformanceService sysMechanicalPerformanceService;
    @Autowired
    private ISysSlumpService sysSlumpService;


    @Value("${file.excel-mechanical-performance}")
    private String mechanicalPerformanceExcelPath;


    @Autowired
    private RedisTemplate redisTemplate;
    private static final String REDIS_KEY = "knowledge:photo:data";
    /**
     * 异常点检测
     */
    @PostMapping("/unusualDetection")
    public AjaxResult unusualDetection(@RequestBody PythonUnusualDTO pythonUnusualDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.unusualDetection(pythonUnusualDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/unusualDetection算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }

    }


    /**
     * 下三角
     */
    @PostMapping("/belowNamic")
    public AjaxResult unusualDetection(@RequestBody PythonBelowNamicDTO pythonBelowNamicDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.belowNamic(pythonBelowNamicDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/belowNamic算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }

    }


    /**
     * 上三角
     */
    @PostMapping("/upper/namic")
    public AjaxResult upperNamic(@RequestBody PythonUpperNamicDTO pythonBelowNamicDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.upperNamic(pythonBelowNamicDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/upper/namic算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果",e);
        }

    }


    /**
     * 全三角
     */
    @PostMapping("/upper/below")
    public AjaxResult upperBelow(@RequestBody PythonUpperBelowDTO pythonUpperBelowDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.upperBelow(pythonUpperBelowDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/modelPkl算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }

    }
    /*----------------------------------------------------------------------------------------------------------------*/


    /**
     * PCA
     */
    @PostMapping("/pca")
    public AjaxResult pca(@RequestBody PcaDTO pcaDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.pca(pcaDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/pca算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);

        }

    }


    /**
     * XGB
     */
    @PostMapping("/xgb")
    public AjaxResult xgb(@RequestBody XgbDTO xgbDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.xgb(xgbDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/xgb算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果",e);
        }

    }


    /**
     * RF
     */
    @PostMapping("/rf")
    public AjaxResult rf(@RequestBody RfDTO rfDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.rf(rfDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/rf算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果",e);
        }

    }


    /**
     * 极限梯度增强树(模型训练)
     */
//    @PostMapping("/limit/tree/second")
//    public AjaxResult limitTreeSecond(@RequestBody LimitTreeDTO limitTreeDTO) throws JsonProcessingException {
//        String excelFilePath = limitTreeDTO.getExcelFilePath();
//        String  modelName = limitTreeDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeDTO.getInputFeatures();
//        List<String> targetFeature = limitTreeDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeDTO.getParamGrid();
//        Integer selectionLater = limitTreeDTO.getSelectionLater();
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures( String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(1);
//
//        AjaxResult ajaxResult = fileClient.limitTreeSecond(limitTreeDTO);
//
//        ObjectMapper objectMapper = new ObjectMapper();
//        // 将 limitTreeDTO 转换为 JSON 字符串
//        String jsonString = objectMapper.writeValueAsString(ajaxResult);
//
//        System.out.println("Response JSON: " + jsonString);
//        // 解析 JSON 字符串
//        JsonNode jsonNode = objectMapper.readTree(jsonString);
//
//        //记录出参
//
//        // 获取 "excelFilePath" 字段
//        String pklUrl = jsonNode.get("modelPklPath").asText();
//
//        String yTrain = jsonNode.get("yTrain").asText();
//
//        System.out.println("我是yTrain"+yTrain);
//
//        String yTest = jsonNode.get("yTest").asText();
//
//        String yPredFinalTrain = jsonNode.get("yPredFinalTrain").asText();
//        String yPredFinalTest = jsonNode.get("yPredFinalTest").asText();
//
//
//        String finalR2Train = jsonNode.get("finalR2Train").asText();
//        String finalR2Test = jsonNode.get("finalR2Test").asText();
//
//
//        String finalMseTrain = jsonNode.get("finalMseTrain").asText();
//        String finalMseTest = jsonNode.get("finalMseTest").asText();
//
//        String bestParams = jsonNode.get("bestParams").asText();
//
//        String metricsInfo = jsonNode.get("metricsInfo").asText();
//
//        sysPkl.setPklUrl(pklUrl);
//
//        sysPkl.setYTrain(yTrain);
//        sysPkl.setYTest(yTest);
//
//        sysPkl.setYPredFinalTrain(yPredFinalTrain);
//        sysPkl.setYPredFinalTest(yPredFinalTest);
//
//        sysPkl.setFinalR2Train(Double.parseDouble(finalR2Train));
//        sysPkl.setFinalR2Test(Double.parseDouble(finalR2Test));
//
//        sysPkl.setFinalMseTrain(Double.parseDouble(finalMseTrain));
//        sysPkl.setFinalMseTest( Double.parseDouble(finalMseTest));
//
//
//        sysPkl.setBestParams(bestParams);
//        sysPkl.setMetricsInfo(metricsInfo);
//
//
//
//
//
//        sysPkl.setUserId(1L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        sysPklService.save(sysPkl);
//
//
//        return ajaxResult;
//    }
    @PostMapping("/limit/tree/second")
    public AjaxResult limitTreeSecond(@RequestBody LimitTreeDTO limitTreeDTO) throws IOException {

//        String excelFilePath = limitTreeDTO.getExcelFilePath();
//        String modelName = limitTreeDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeDTO.getInputFeatures();
//        List<String> targetFeature = limitTreeDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeDTO.getParamGrid();
//        Integer selectionLater = limitTreeDTO.getSelectionLater();
//
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures(String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(1L);

        // 调用服务获取结果
        try {
            AjaxResult ajaxResult = fileClient.limitTreeSecond(limitTreeDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/limit/tree/second算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果",e);
        }

//        ObjectMapper objectMapper = new ObjectMapper();
//
//        // 转换为 JSON 字符串（如果 data 是 Map/Object）
//        String jsonData = objectMapper.writeValueAsString(ajaxResult);
//
//        // 读取成 JsonNode，便于进一步提取字段
//        JsonNode rootNode = objectMapper.readTree(jsonData);
//        JsonNode pklUrk = rootNode.get("modelPklPath");
//
//        JsonNode yTrain = rootNode.get("yTrain");
//        JsonNode yTest = rootNode.get("yTest");
//
//        JsonNode yPredFinalTrain = rootNode.get("yPredFinalTrain");
//        JsonNode yPredFinalTest = rootNode.get("yPredFinalTest");
//
//
//        JsonNode finalR2Train = rootNode.get("finalR2Train");
//        JsonNode finalR2Test = rootNode.get("finalR2Test");
//
//
//        JsonNode finalMseTrain = rootNode.get("finalMseTrain");
//        JsonNode finalMseTest = rootNode.get("finalMseTest");
//
//
//
//        JsonNode bestParams = rootNode.get("bestParams");
//        JsonNode metricsInfo = rootNode.get("metricsInfo");
//
//
//
//        sysPkl.setPklUrl(String.valueOf(pklUrk));
//        sysPkl.setYTrain(String.valueOf(yTrain));
//        // 或者直接存储 List<List<Double>> 类型
//        sysPkl.setYTest(String.valueOf(yTest));
//
//        sysPkl.setFinalR2Train(finalR2Train.asDouble());
//        sysPkl.setFinalR2Test(finalR2Test.asDouble());
//
//
//        sysPkl.setYPredFinalTrain(String.valueOf(yPredFinalTrain));
//        sysPkl.setYPredFinalTest(String.valueOf(yPredFinalTest));
//
//        sysPkl.setFinalMseTrain(finalMseTrain.asDouble());
//        sysPkl.setFinalMseTest(finalMseTest.asDouble());
//
//
//
//        sysPkl.setBestParams(String.valueOf(bestParams));
//        sysPkl.setMetricsInfo(String.valueOf(metricsInfo));
//
//
//
//
//        // 设置其他字段
//        sysPkl.setUserId(2L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        // 保存 SysPkl 到数据库
//        sysPklService.save(sysPkl);



    }


    /**
     * 集成增强模型   (模型训练)
     */
    @PostMapping("/integrat/enhance/second")
    public AjaxResult integratEnhanceSecond(@RequestBody LimitTreeSecondDTO limitTreeSecondDTO) throws IOException {


//        String excelFilePath = limitTreeSecondDTO.getExcelFilePath();
//        String modelName = limitTreeSecondDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeSecondDTO.getInputFeatures();
//    List<String> targetFeature = limitTreeSecondDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeSecondDTO.getParamGrid();
//        Integer selectionLater = limitTreeSecondDTO.getSelectionLater();
//
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures(String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(2);
//
//
        try {
            AjaxResult ajaxResult = fileClient.integratEnhanceSecond(limitTreeSecondDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/integrat/enhance/second算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }
//
//
//        ObjectMapper objectMapper = new ObjectMapper();
//
//        // 转换为 JSON 字符串（如果 data 是 Map/Object）
//        String jsonData = objectMapper.writeValueAsString(ajaxResult);
//
//        // 读取成 JsonNode，便于进一步提取字段
//        JsonNode rootNode = objectMapper.readTree(jsonData);
//        JsonNode pklUrk = rootNode.get("modelPklPath");
//
//        JsonNode yTrain = rootNode.get("yTrain");
//        JsonNode yTest = rootNode.get("yTest");
//
//        JsonNode yPredFinalTrain = rootNode.get("yPredFinalTrain");
//        JsonNode yPredFinalTest = rootNode.get("yPredFinalTest");
//
//
//        JsonNode finalR2Train = rootNode.get("finalR2Train");
//        JsonNode finalR2Test = rootNode.get("finalR2Test");
//
//
//        JsonNode finalMseTrain = rootNode.get("finalMseTrain");
//        JsonNode finalMseTest = rootNode.get("finalMseTest");
//
//
//
//        JsonNode bestParams = rootNode.get("bestParams");
//        JsonNode metricsInfo = rootNode.get("metricsInfo");
//
//
//
//
//        sysPkl.setPklUrl(String.valueOf(pklUrk));
//        sysPkl.setYTrain(String.valueOf(yTrain));
//        // 或者直接存储 List<List<Double>> 类型
//        sysPkl.setYTest(String.valueOf(yTest));
//
//        sysPkl.setFinalR2Train(finalR2Train.asDouble());
//        sysPkl.setFinalR2Test(finalR2Test.asDouble());
//
//
//        sysPkl.setYPredFinalTrain(String.valueOf(yPredFinalTrain));
//        sysPkl.setYPredFinalTest(String.valueOf(yPredFinalTest));
//
//        sysPkl.setFinalMseTrain(finalMseTrain.asDouble());
//        sysPkl.setFinalMseTest(finalMseTest.asDouble());
//
//
//
//        sysPkl.setBestParams(String.valueOf(bestParams));
//        sysPkl.setMetricsInfo(String.valueOf(metricsInfo));
//
//
//
//
//        // 设置其他字段
//        sysPkl.setUserId(2L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        // 保存 SysPkl 到数据库
//        sysPklService.save(sysPkl);


    }


    /**
     * 自编码特征筛选模型  (模型训练)
     */
    @PostMapping("/own/code/feature/select/second")
    public AjaxResult ownCodeFeatureSelectSecond(@RequestBody LimitTreeDTO limitTreeDTO) throws IOException {


//        String excelFilePath = limitTreeDTO.getExcelFilePath();
//        String modelName = limitTreeDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeDTO.getInputFeatures();
//        List<String> targetFeature = limitTreeDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeDTO.getParamGrid();
//        Integer selectionLater = limitTreeDTO.getSelectionLater();
//
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures(String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(3);
        try {
            AjaxResult ajaxResult = fileClient.ownCodeFeatureSelectSecond(limitTreeDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/own/code/feature/select/second算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }


//        ObjectMapper objectMapper = new ObjectMapper();
//
//        // 转换为 JSON 字符串（如果 data 是 Map/Object）
//        String jsonData = objectMapper.writeValueAsString(ajaxResult);
//
//        // 读取成 JsonNode，便于进一步提取字段
//        JsonNode rootNode = objectMapper.readTree(jsonData);
//        JsonNode pklUrk = rootNode.get("modelPklPath");
//
//        JsonNode yTrain = rootNode.get("yTrain");
//        JsonNode yTest = rootNode.get("yTest");
//
//        JsonNode yPredFinalTrain = rootNode.get("yPredFinalTrain");
//        JsonNode yPredFinalTest = rootNode.get("yPredFinalTest");
//
//
//        JsonNode finalR2Train = rootNode.get("finalR2Train");
//        JsonNode finalR2Test = rootNode.get("finalR2Test");
//
//
//        JsonNode finalMseTrain = rootNode.get("finalMseTrain");
//        JsonNode finalMseTest = rootNode.get("finalMseTest");
//
//
//
//        JsonNode bestParams = rootNode.get("bestParams");
//        JsonNode metricsInfo = rootNode.get("metricsInfo");
//
//
//
//
//        sysPkl.setPklUrl(String.valueOf(pklUrk));
//        sysPkl.setYTrain(String.valueOf(yTrain));
//        // 或者直接存储 List<List<Double>> 类型
//        sysPkl.setYTest(String.valueOf(yTest));
//
//        sysPkl.setFinalR2Train(finalR2Train.asDouble());
//        sysPkl.setFinalR2Test(finalR2Test.asDouble());
//
//
//        sysPkl.setYPredFinalTrain(String.valueOf(yPredFinalTrain));
//        sysPkl.setYPredFinalTest(String.valueOf(yPredFinalTest));
//
//        sysPkl.setFinalMseTrain(finalMseTrain.asDouble());
//        sysPkl.setFinalMseTest(finalMseTest.asDouble());
//
//
//
//        sysPkl.setBestParams(String.valueOf(bestParams));
//        sysPkl.setMetricsInfo(String.valueOf(metricsInfo));
//
//
//
//
//        // 设置其他字段
//        sysPkl.setUserId(2L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        // 保存 SysPkl 到数据库
//        sysPklService.save(sysPkl);



    }


    /*------------------------------------------------------------------------------------------------------------*/


    /**
     * 极限梯度增强树(模型优化验证)
     */
    @PostMapping("/limit/tree")
    public AjaxResult limitTree(@RequestBody LimitTreeDTO limitTreeDTO) throws JsonProcessingException {
//        String excelFilePath = limitTreeDTO.getExcelFilePath();
//        String modelName = limitTreeDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeDTO.getInputFeatures();
//        List<String> targetFeature = limitTreeDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeDTO.getParamGrid();
//        Integer selectionLater = limitTreeDTO.getSelectionLater();
//
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures(String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(4);
//
        try {
            AjaxResult ajaxResult = fileClient.limitTree(limitTreeDTO);

            return ajaxResult;
        } catch (Exception e) {

            log.error("/limit/tree算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }
//
//        ObjectMapper objectMapper = new ObjectMapper();
//
//        // 转换为 JSON 字符串（如果 data 是 Map/Object）
//        String jsonData = objectMapper.writeValueAsString(ajaxResult);
//
//        // 读取成 JsonNode，便于进一步提取字段
//        JsonNode rootNode = objectMapper.readTree(jsonData);
//        JsonNode pklUrk = rootNode.get("modelPklPath");
//
//        JsonNode yTrain = rootNode.get("yTrain");
//        JsonNode yTest = rootNode.get("yTest");
//
//        JsonNode yPredFinalTrain = rootNode.get("yPredFinalTrain");
//        JsonNode yPredFinalTest = rootNode.get("yPredFinalTest");
//
//
//        JsonNode finalR2Train = rootNode.get("finalR2Train");
//        JsonNode finalR2Test = rootNode.get("finalR2Test");
//
//
//        JsonNode finalMseTrain = rootNode.get("finalMseTrain");
//        JsonNode finalMseTest = rootNode.get("finalMseTest");
//
//
//
//        JsonNode bestParams = rootNode.get("bestParams");
//        JsonNode metricsInfo = rootNode.get("metricsInfo");
//
//
//
//
//        sysPkl.setPklUrl(String.valueOf(pklUrk));
//        sysPkl.setYTrain(String.valueOf(yTrain));
//        // 或者直接存储 List<List<Double>> 类型
//        sysPkl.setYTest(String.valueOf(yTest));
//
//        sysPkl.setFinalR2Train(finalR2Train.asDouble());
//        sysPkl.setFinalR2Test(finalR2Test.asDouble());
//
//
//        sysPkl.setYPredFinalTrain(String.valueOf(yPredFinalTrain));
//        sysPkl.setYPredFinalTest(String.valueOf(yPredFinalTest));
//
//        sysPkl.setFinalMseTrain(finalMseTrain.asDouble());
//        sysPkl.setFinalMseTest(finalMseTest.asDouble());
//
//
//
//        sysPkl.setBestParams(String.valueOf(bestParams));
//        sysPkl.setMetricsInfo(String.valueOf(metricsInfo));
//
//
//
//
//        // 设置其他字段
//        sysPkl.setUserId(2L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        // 保存 SysPkl 到数据库
//        sysPklService.save(sysPkl);

    }


    /**
     * 集成增强模型(模型优化验证)
     */
    @PostMapping("/integrat/enhance")
    public AjaxResult integratEnhance(@RequestBody LimitTreeSecondDTO limitTreeSecondDTO) throws JsonProcessingException {
//        String excelFilePath = limitTreeSecondDTO.getExcelFilePath();
//        String modelName = limitTreeSecondDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeSecondDTO.getInputFeatures();
//       List<String> targetFeature = limitTreeSecondDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeSecondDTO.getParamGrid();
//        Integer selectionLater = limitTreeSecondDTO.getSelectionLater();
//
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures(String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(5);
        try {
            AjaxResult ajaxResult = fileClient.integratEnhance(limitTreeSecondDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/integrat/enhance算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }
//
//        ObjectMapper objectMapper = new ObjectMapper();
//
//        // 转换为 JSON 字符串（如果 data 是 Map/Object）
//        String jsonData = objectMapper.writeValueAsString(ajaxResult);
//
//        // 读取成 JsonNode，便于进一步提取字段
//        JsonNode rootNode = objectMapper.readTree(jsonData);
//        JsonNode pklUrk = rootNode.get("modelPklPath");
//
//        JsonNode yTrain = rootNode.get("yTrain");
//        JsonNode yTest = rootNode.get("yTest");
//
//        JsonNode yPredFinalTrain = rootNode.get("yPredFinalTrain");
//        JsonNode yPredFinalTest = rootNode.get("yPredFinalTest");
//
//
//        JsonNode finalR2Train = rootNode.get("finalR2Train");
//        JsonNode finalR2Test = rootNode.get("finalR2Test");
//
//
//        JsonNode finalMseTrain = rootNode.get("finalMseTrain");
//        JsonNode finalMseTest = rootNode.get("finalMseTest");
//
//
//
//        JsonNode bestParams = rootNode.get("bestParams");
//        JsonNode metricsInfo = rootNode.get("metricsInfo");
//
//
//
//
//        sysPkl.setPklUrl(String.valueOf(pklUrk));
//        sysPkl.setYTrain(String.valueOf(yTrain));
//        // 或者直接存储 List<List<Double>> 类型
//        sysPkl.setYTest(String.valueOf(yTest));
//
//        sysPkl.setFinalR2Train(finalR2Train.asDouble());
//        sysPkl.setFinalR2Test(finalR2Test.asDouble());
//
//
//        sysPkl.setYPredFinalTrain(String.valueOf(yPredFinalTrain));
//        sysPkl.setYPredFinalTest(String.valueOf(yPredFinalTest));
//
//        sysPkl.setFinalMseTrain(finalMseTrain.asDouble());
//        sysPkl.setFinalMseTest(finalMseTest.asDouble());
//
//
//
//        sysPkl.setBestParams(String.valueOf(bestParams));
//        sysPkl.setMetricsInfo(String.valueOf(metricsInfo));
//
//
//
//
//        // 设置其他字段
//        sysPkl.setUserId(2L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        // 保存 SysPkl 到数据库
//        sysPklService.save(sysPkl);


    }


    /**
     * 自编码特征筛选模型(模型优化验证)
     */
    @PostMapping("/own/code/feature/select")
    public AjaxResult ownCodeFeatureSelect(@RequestBody LimitTreeSecondDTO limitTreeSecondDTO) throws JsonProcessingException {
//        String excelFilePath = limitTreeSecondDTO.getExcelFilePath();
//        String modelName = limitTreeSecondDTO.getModelSavePath();
//        List<String> inputFeatures = limitTreeSecondDTO.getInputFeatures();
//       List<String> targetFeature = limitTreeSecondDTO.getTargetFeature();
//        Map<String, List<Double>> paramGrid = limitTreeSecondDTO.getParamGrid();
//        Integer selectionLater = limitTreeSecondDTO.getSelectionLater();
//
//        SysPkl sysPkl = new SysPkl();
//        //记录入参
//        sysPkl.setExcelFilePath(excelFilePath);
//        sysPkl.setModelName(modelName);
//        sysPkl.setInputFeatures(String.valueOf(inputFeatures));
//        sysPkl.setTargetFeature(String.valueOf(targetFeature));
//        sysPkl.setParamGrid(String.valueOf(paramGrid));
//        sysPkl.setSelectionLater(String.valueOf(selectionLater));
//        //记录类型
//        sysPkl.setType(6);
        try {
            AjaxResult ajaxResult = fileClient.ownCodeFeatureSelect(limitTreeSecondDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/own/code/feature/select算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }
//
//        ObjectMapper objectMapper = new ObjectMapper();
//
//        // 转换为 JSON 字符串（如果 data 是 Map/Object）
//        String jsonData = objectMapper.writeValueAsString(ajaxResult);
//
//        // 读取成 JsonNode，便于进一步提取字段
//        JsonNode rootNode = objectMapper.readTree(jsonData);
//        JsonNode pklUrk = rootNode.get("modelPklPath");
//
//        JsonNode yTrain = rootNode.get("yTrain");
//        JsonNode yTest = rootNode.get("yTest");
//
//        JsonNode yPredFinalTrain = rootNode.get("yPredFinalTrain");
//        JsonNode yPredFinalTest = rootNode.get("yPredFinalTest");
//
//
//        JsonNode finalR2Train = rootNode.get("finalR2Train");
//        JsonNode finalR2Test = rootNode.get("finalR2Test");
//
//
//        JsonNode finalMseTrain = rootNode.get("finalMseTrain");
//        JsonNode finalMseTest = rootNode.get("finalMseTest");
//
//
//
//        JsonNode bestParams = rootNode.get("bestParams");
//        JsonNode metricsInfo = rootNode.get("metricsInfo");
//
//
//
//
//        sysPkl.setPklUrl(String.valueOf(pklUrk));
//        sysPkl.setYTrain(String.valueOf(yTrain));
//        // 或者直接存储 List<List<Double>> 类型
//        sysPkl.setYTest(String.valueOf(yTest));
//
//        sysPkl.setFinalR2Train(finalR2Train.asDouble());
//        sysPkl.setFinalR2Test(finalR2Test.asDouble());
//
//
//        sysPkl.setYPredFinalTrain(String.valueOf(yPredFinalTrain));
//        sysPkl.setYPredFinalTest(String.valueOf(yPredFinalTest));
//
//        sysPkl.setFinalMseTrain(finalMseTrain.asDouble());
//        sysPkl.setFinalMseTest(finalMseTest.asDouble());
//
//
//
//        sysPkl.setBestParams(String.valueOf(bestParams));
//        sysPkl.setMetricsInfo(String.valueOf(metricsInfo));
//
//
//
//
//        // 设置其他字段
//        sysPkl.setUserId(2L);
//        sysPkl.setCreateTime(LocalDateTime.now());
//
//        // 保存 SysPkl 到数据库
//        sysPklService.save(sysPkl);


    }




    /*------------------------------------------------------------------------------------------------------------*/

    /**
     * 上传模型接口
     */
    @PostMapping("/modelPkl")
    public AjaxResult modelPkl(@RequestBody ModelPklDTO modelPklDTO) {
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.modelPkl(modelPklDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("/modelPkl算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }

    }





    /*------------------------------------------------------------------------------------------------------------*/


    /**
     * 自编码特征筛选模型(模型优化验证)
     *
     * @param pklDTO   请求参数，包含要下载的 pkl 文件路径
     * @param response HTTP 响应对象
     * @throws IOException 可能抛出的 IO 异常
     */
//    @PostMapping("/downloadPkl")
//    public void downloadPkl(@RequestBody PklDTO pklDTO, HttpServletResponse response) throws IOException {
//        // 获取请求中的文件路径
//        String pklPath = pklDTO.getPklUrl();
//        File file = new File(pklPath);
//
//        // 1. 检查文件是否存在
//        if (!file.exists()) {
//            // 设置 HTTP 响应类型为 JSON，并返回错误信息
//            response.setContentType("application/json;charset=UTF-8");
//            response.getWriter().write("{\"code\":500, \"message\":\"文件不存在\"}");
//            return;
//        }
//
//        // 2. 设置 HTTP 响应头，让浏览器识别为下载文件
//        response.setContentType("application/octet-stream"); // 设置 MIME 类型，表示二进制流
//        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
//        response.setContentLengthLong(file.length()); // 设置文件大小，防止下载异常
//
//        // 3. 通过 Files.copy() 直接复制文件内容到 HTTP 响应输出流
//        Files.copy(file.toPath(), response.getOutputStream());
//
//        // 4. 刷新缓冲区，确保数据全部写出
//        response.flushBuffer();
//    }
//
//
    @PostMapping("/downloadPkl")
    public void downloadPkl(@RequestBody PklDTO pklDTO, HttpServletResponse response) {
        String pklPath = pklDTO.getPklUrl();
        File file = new File(pklPath);

        // 检查文件是否存在
        if (!file.exists()) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // 设置响应头
        response.setContentType("application/octet-stream");
        try {
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        response.setContentLengthLong(file.length());

        // 写文件到输出流
        try (OutputStream os = response.getOutputStream()) {
            Files.copy(file.toPath(), os);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    /*-----------------------------------------------------------------*/
    @PostMapping("/downloadExcel")
    public void downloadExcel(@RequestBody PklDTO pklDTO, HttpServletResponse response) {
        String excelPath = pklDTO.getExcelUrl(); // 获取 Excel 文件的路径
        File file = new File(excelPath);

        // 检查文件是否存在
        if (!file.exists()) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // 设置响应头
        response.setContentType("application/vnd.ms-excel"); // 设置 Excel 文件的 MIME 类型
        try {
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        response.setContentLengthLong(file.length()); // 设置文件大小

        // 写文件到输出流
        try (OutputStream os = response.getOutputStream();
             FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
    /*----------------------------------上传pkl----------------------------------*/



    @PostMapping("/uploadPkl")
    @Transactional
    public AjaxResult upload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return AjaxResult.error("上传失败，文件为空");
        }

        try {
            // 设置上传路径
            String uploadDir = uploadPklPath;
            File dir = new File(uploadDir);

            if (!dir.exists()) {
                dir.mkdirs(); // 创建目录
            }

            // 使用当前时间戳+文件名避免重复
            String originalFilename = file.getOriginalFilename();
            String fileName = System.currentTimeMillis() + "_" + originalFilename;
            File dest = new File(uploadDir + fileName);

            // 保存文件
            file.transferTo(dest);

            // 去掉文件名中的 .pkl 后缀
            String fileNameWithoutExtension = originalFilename.replace(".pkl", "");

            // 返回上传成功的文件路径
            String filePath = dest.getAbsolutePath();

            HashMap<Object, Object> map = new HashMap<>();
            map.put("name", fileNameWithoutExtension);  // 使用去掉 .pkl 后缀的文件名
            map.put("filePath", filePath);
            return AjaxResult.success("上传成功", map);
        } catch (IOException e) {
            e.printStackTrace();
            return AjaxResult.error("上传失败：" + e.getMessage());
        }
    }



    /*------------------------------------------------------------------------------------------------------------*/

    /**
     * 异常点检测Second
     */
    @PostMapping("/unusualDetection/second")
    public AjaxResult unusualDetectionSecond(@RequestBody PythonUnusualDTO pythonUnusualDTO) {

        List<String> selectFeature = pythonUnusualDTO.getSelectFeature();

        // 处理 selectFeature 替换
        replaceFeature(selectFeature, "石掺量", Arrays.asList("石5-10mm掺量", "石5-25mm掺量", "石20-40mm掺量", "石10-20mm掺量", "石10-30mm掺量", "石0-10mm掺量", "石20-31.5mm掺量"));
        replaceFeature(selectFeature, "石堆积密度", Arrays.asList("石5-10mm堆积密度(kg/m³)", "石5-25mm堆积密度(kg/m³)", "石20-40mm堆积密度(kg/m³)", "石10-20mm堆积密度(kg/m³)", "石10-30mm堆积密度(kg/m³)", "石0-10mm堆积密度(kg/m³)", "石20-31.5mm堆积密度(kg/m³)"));
        replaceFeature(selectFeature, "石紧密密度", Arrays.asList("石5-10mm紧密密度(kg/m³)", "石5-25mm紧密密度(kg/m³)", "石20-40mm紧密密度(kg/m³)", "石10-20mm紧密密度(kg/m³)", "石10-30mm紧密密度(kg/m³)", "石0-10mm紧密密度(kg/m³)", "石20-31.5mm紧密密度(kg/m³)"));
        replaceFeature(selectFeature, "石表观密度", Arrays.asList("石5-10mm表观密度(kg/m³)", "石5-25mm表观密度(kg/m³)", "石20-40mm表观密度(kg/m³)", "石10-20mm表观密度(kg/m³)", "石10-30mm表观密度(kg/m³)", "石0-10mm表观密度(kg/m³)", "石20-31.5mm表观密度(kg/m³)"));

        replaceFeature(selectFeature, "砂掺量", Arrays.asList("河砂粗3.1-3.7mm掺量", "河砂中2.3-3.0mm掺量", "河砂细1.6-2.2mm掺量", "机制砂中2.3-3.0mm掺量", "机制砂粗3.1-3.7mm掺量", "机制砂细1.6-2.2mm掺量", "机制砂0-4.75mm掺量", "机制砂0-9mm掺量"));
        replaceFeature(selectFeature, "砂细度", Arrays.asList("河砂粗3.1-3.7mm细度", "河砂中2.3-3.0mm细度", "河砂细1.6-2.2mm细度", "机制砂中2.3-3.0mm细度", "机制砂粗3.1-3.7mm细度", "机制砂细1.6-2.2mm细度", "机制砂0-4.75mm细度", "机制砂0-9mm细度"));
        replaceFeature(selectFeature, "砂堆积密度", Arrays.asList("河砂粗3.1-3.7mm堆积密度(kg/m³)", "河砂中2.3-3.0mm堆积密度(kg/m³)", "河砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂中2.3-3.0mm堆积密度(kg/m³)", "机制砂粗3.1-3.7mm堆积密度(kg/m³)", "机制砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂0-4.75mm堆积密度(kg/m³)", "机制砂0-9mm堆积密度(kg/m³)"));
        replaceFeature(selectFeature, "砂紧密密度", Arrays.asList("河砂粗3.1-3.7mm紧密密度(kg/m³)", "河砂中2.3-3.0mm紧密密度(kg/m³)", "河砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂中2.3-3.0mm紧密密度(kg/m³)", "机制砂粗3.1-3.7mm紧密密度(kg/m³)", "机制砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂0-4.75mm紧密密度(kg/m³)", "机制砂0-9mm紧密密度(kg/m³)"));
        replaceFeature(selectFeature, "砂表观密度", Arrays.asList("河砂粗3.1-3.7mm表观密度(kg/m³)", "河砂中2.3-3.0mm表观密度(kg/m³)", "河砂细1.6-2.2mm表观密度(kg/m³)", "机制砂中2.3-3.0mm表观密度(kg/m³)", "机制砂粗3.1-3.7mm表观密度(kg/m³)", "机制砂细1.6-2.2mm表观密度(kg/m³)", "机制砂0-4.75mm表观密度(kg/m³)", "机制砂0-9mm表观密度(kg/m³)"));

        // 递归检查 pythonBelowNamicDTO 中是否包含 NaN
        if (containsNaN(pythonUnusualDTO)) {
            return AjaxResult.error("数据错误，包含 NaN");
        }

        // 调用接口
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.unusualDetection(pythonUnusualDTO);
            // 处理返回结果，去除 NaN
            cleanNaNValues(ajaxResult);

            return ajaxResult;
        } catch (Exception e) {
            log.error("/unusualDetection/second算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }



    }


//    /**
//     * 下三角Second
//     */
//    @PostMapping("/belowNamic/second")
//    public AjaxResult unusualDetectionSecond(@RequestBody PythonBelowNamicDTO pythonBelowNamicDTO) {
//
//        List<String> selectFeature = pythonBelowNamicDTO.getSelectFeature();
//
//        // 处理 selectFeature 替换
//        replaceFeature(selectFeature, "石掺量", Arrays.asList("石5-10mm掺量", "石5-25mm掺量", "石20-40mm掺量", "石10-20mm掺量", "石10-30mm掺量", "石0-10mm掺量", "石20-31.5mm掺量"));
//        replaceFeature(selectFeature, "石堆积密度", Arrays.asList("石5-10mm堆积密度(kg/m³)", "石5-25mm堆积密度(kg/m³)", "石20-40mm堆积密度(kg/m³)", "石10-20mm堆积密度(kg/m³)", "石10-30mm堆积密度(kg/m³)", "石0-10mm堆积密度(kg/m³)", "石20-31.5mm堆积密度(kg/m³)"));
//        replaceFeature(selectFeature, "石紧密密度", Arrays.asList("石5-10mm紧密密度(kg/m³)", "石5-25mm紧密密度(kg/m³)", "石20-40mm紧密密度(kg/m³)", "石10-20mm紧密密度(kg/m³)", "石10-30mm紧密密度(kg/m³)", "石0-10mm紧密密度(kg/m³)", "石20-31.5mm紧密密度(kg/m³)"));
//        replaceFeature(selectFeature, "石表观密度", Arrays.asList("石5-10mm表观密度(kg/m³)", "石5-25mm表观密度(kg/m³)", "石20-40mm表观密度(kg/m³)", "石10-20mm表观密度(kg/m³)", "石10-30mm表观密度(kg/m³)", "石0-10mm表观密度(kg/m³)", "石20-31.5mm表观密度(kg/m³)"));
//
//        replaceFeature(selectFeature, "砂掺量", Arrays.asList("河砂粗3.1-3.7mm掺量", "河砂中2.3-3.0mm掺量", "河砂细1.6-2.2mm掺量", "机制砂中2.3-3.0mm掺量", "机制砂粗3.1-3.7mm掺量", "机制砂细1.6-2.2mm掺量", "机制砂0-4.75mm掺量", "机制砂0-9mm掺量"));
//        replaceFeature(selectFeature, "砂细度", Arrays.asList("河砂粗3.1-3.7mm细度", "河砂中2.3-3.0mm细度", "河砂细1.6-2.2mm细度", "机制砂中2.3-3.0mm细度", "机制砂粗3.1-3.7mm细度", "机制砂细1.6-2.2mm细度", "机制砂0-4.75mm细度", "机制砂0-9mm细度"));
//        replaceFeature(selectFeature, "砂堆积密度", Arrays.asList("河砂粗3.1-3.7mm堆积密度(kg/m³)", "河砂中2.3-3.0mm堆积密度(kg/m³)", "河砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂中2.3-3.0mm堆积密度(kg/m³)", "机制砂粗3.1-3.7mm堆积密度(kg/m³)", "机制砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂0-4.75mm堆积密度(kg/m³)", "机制砂0-9mm堆积密度(kg/m³)"));
//        replaceFeature(selectFeature, "砂紧密密度", Arrays.asList("河砂粗3.1-3.7mm紧密密度(kg/m³)", "河砂中2.3-3.0mm紧密密度(kg/m³)", "河砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂中2.3-3.0mm紧密密度(kg/m³)", "机制砂粗3.1-3.7mm紧密密度(kg/m³)", "机制砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂0-4.75mm紧密密度(kg/m³)", "机制砂0-9mm紧密密度(kg/m³)"));
//        replaceFeature(selectFeature, "砂表观密度", Arrays.asList("河砂粗3.1-3.7mm表观密度(kg/m³)", "河砂中2.3-3.0mm表观密度(kg/m³)", "河砂细1.6-2.2mm表观密度(kg/m³)", "机制砂中2.3-3.0mm表观密度(kg/m³)", "机制砂粗3.1-3.7mm表观密度(kg/m³)", "机制砂细1.6-2.2mm表观密度(kg/m³)", "机制砂0-4.75mm表观密度(kg/m³)", "机制砂0-9mm表观密度(kg/m³)"));
//
//        // 递归检查 pythonBelowNamicDTO 中是否包含 NaN
//        if (containsNaN(pythonBelowNamicDTO)) {
//            return AjaxResult.error("数据错误，包含 NaN");
//        }
//
//        // 调用接口
//        AjaxResult ajaxResult = null;
//        try {
//            ajaxResult = fileClient.belowNamic(pythonBelowNamicDTO);
//            // 处理返回结果，去除 NaN
//            cleanNaNValues(ajaxResult);
//
//            return ajaxResult;
//        } catch (Exception e) {
//            log.error("/belowNamic/second算法报错:{}",e.getMessage());
//            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
//        }
//
//
//    }
//
//
//    /**
//     * 上三角Second
//     */
//
//    @PostMapping("/upper/namic/second")
//    public AjaxResult upperNamicSecond(@RequestBody PythonUpperNamicDTO pythonBelowNamicDTO) {
//        List<String> selectFeature = pythonBelowNamicDTO.getSelectFeature();
//
//        // 处理 selectFeature 替换
//        replaceFeature(selectFeature, "石掺量", Arrays.asList("石5-10mm掺量", "石5-25mm掺量", "石20-40mm掺量", "石10-20mm掺量", "石10-30mm掺量", "石0-10mm掺量", "石20-31.5mm掺量"));
//        replaceFeature(selectFeature, "石堆积密度", Arrays.asList("石5-10mm堆积密度(kg/m³)", "石5-25mm堆积密度(kg/m³)", "石20-40mm堆积密度(kg/m³)", "石10-20mm堆积密度(kg/m³)", "石10-30mm堆积密度(kg/m³)", "石0-10mm堆积密度(kg/m³)", "石20-31.5mm堆积密度(kg/m³)"));
//        replaceFeature(selectFeature, "石紧密密度", Arrays.asList("石5-10mm紧密密度(kg/m³)", "石5-25mm紧密密度(kg/m³)", "石20-40mm紧密密度(kg/m³)", "石10-20mm紧密密度(kg/m³)", "石10-30mm紧密密度(kg/m³)", "石0-10mm紧密密度(kg/m³)", "石20-31.5mm紧密密度(kg/m³)"));
//        replaceFeature(selectFeature, "石表观密度", Arrays.asList("石5-10mm表观密度(kg/m³)", "石5-25mm表观密度(kg/m³)", "石20-40mm表观密度(kg/m³)", "石10-20mm表观密度(kg/m³)", "石10-30mm表观密度(kg/m³)", "石0-10mm表观密度(kg/m³)", "石20-31.5mm表观密度(kg/m³)"));
//
//        replaceFeature(selectFeature, "砂掺量", Arrays.asList("河砂粗3.1-3.7mm掺量", "河砂中2.3-3.0mm掺量", "河砂细1.6-2.2mm掺量", "机制砂中2.3-3.0mm掺量", "机制砂粗3.1-3.7mm掺量", "机制砂细1.6-2.2mm掺量", "机制砂0-4.75mm掺量", "机制砂0-9mm掺量"));
//        replaceFeature(selectFeature, "砂细度", Arrays.asList("河砂粗3.1-3.7mm细度", "河砂中2.3-3.0mm细度", "河砂细1.6-2.2mm细度", "机制砂中2.3-3.0mm细度", "机制砂粗3.1-3.7mm细度", "机制砂细1.6-2.2mm细度", "机制砂0-4.75mm细度", "机制砂0-9mm细度"));
//        replaceFeature(selectFeature, "砂堆积密度", Arrays.asList("河砂粗3.1-3.7mm堆积密度(kg/m³)", "河砂中2.3-3.0mm堆积密度(kg/m³)", "河砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂中2.3-3.0mm堆积密度(kg/m³)", "机制砂粗3.1-3.7mm堆积密度(kg/m³)", "机制砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂0-4.75mm堆积密度(kg/m³)", "机制砂0-9mm堆积密度(kg/m³)"));
//        replaceFeature(selectFeature, "砂紧密密度", Arrays.asList("河砂粗3.1-3.7mm紧密密度(kg/m³)", "河砂中2.3-3.0mm紧密密度(kg/m³)", "河砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂中2.3-3.0mm紧密密度(kg/m³)", "机制砂粗3.1-3.7mm紧密密度(kg/m³)", "机制砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂0-4.75mm紧密密度(kg/m³)", "机制砂0-9mm紧密密度(kg/m³)"));
//        replaceFeature(selectFeature, "砂表观密度", Arrays.asList("河砂粗3.1-3.7mm表观密度(kg/m³)", "河砂中2.3-3.0mm表观密度(kg/m³)", "河砂细1.6-2.2mm表观密度(kg/m³)", "机制砂中2.3-3.0mm表观密度(kg/m³)", "机制砂粗3.1-3.7mm表观密度(kg/m³)", "机制砂细1.6-2.2mm表观密度(kg/m³)", "机制砂0-4.75mm表观密度(kg/m³)", "机制砂0-9mm表观密度(kg/m³)"));
//
//        // 递归检查 pythonBelowNamicDTO 中是否包含 NaN
//        if (containsNaN(pythonBelowNamicDTO)) {
//            return AjaxResult.error("数据错误，包含 NaN");
//        }
//
//        // 调用接口
//        AjaxResult ajaxResult = null;
//        try {
//            ajaxResult = fileClient.upperNamic(pythonBelowNamicDTO);
//            // 处理返回结果，去除 NaN
//            cleanNaNValues(ajaxResult);
//
//            return ajaxResult;
//        } catch (Exception e) {
//            log.error("/upper/namic/second算法报错:{}",e.getMessage());
//            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
//        }
//
//
//    }
//
//
//    /**
//     * 全三角Second
//     */
//    @PostMapping("/upper/below/second")
//    public AjaxResult upperBelowSecond(@RequestBody PythonUpperBelowDTO pythonUpperBelowDTO) {
//        List<String> selectFeature = pythonUpperBelowDTO.getSelectFeature();
//
//        // 处理 selectFeature 替换
//        replaceFeature(selectFeature, "石掺量", Arrays.asList("石5-10mm掺量", "石5-25mm掺量", "石20-40mm掺量", "石10-20mm掺量", "石10-30mm掺量", "石0-10mm掺量", "石20-31.5mm掺量"));
//        replaceFeature(selectFeature, "石堆积密度", Arrays.asList("石5-10mm堆积密度(kg/m³)", "石5-25mm堆积密度(kg/m³)", "石20-40mm堆积密度(kg/m³)", "石10-20mm堆积密度(kg/m³)", "石10-30mm堆积密度(kg/m³)", "石0-10mm堆积密度(kg/m³)", "石20-31.5mm堆积密度(kg/m³)"));
//        replaceFeature(selectFeature, "石紧密密度", Arrays.asList("石5-10mm紧密密度(kg/m³)", "石5-25mm紧密密度(kg/m³)", "石20-40mm紧密密度(kg/m³)", "石10-20mm紧密密度(kg/m³)", "石10-30mm紧密密度(kg/m³)", "石0-10mm紧密密度(kg/m³)", "石20-31.5mm紧密密度(kg/m³)"));
//        replaceFeature(selectFeature, "石表观密度", Arrays.asList("石5-10mm表观密度(kg/m³)", "石5-25mm表观密度(kg/m³)", "石20-40mm表观密度(kg/m³)", "石10-20mm表观密度(kg/m³)", "石10-30mm表观密度(kg/m³)", "石0-10mm表观密度(kg/m³)", "石20-31.5mm表观密度(kg/m³)"));
//
//        replaceFeature(selectFeature, "砂掺量", Arrays.asList("河砂粗3.1-3.7mm掺量", "河砂中2.3-3.0mm掺量", "河砂细1.6-2.2mm掺量", "机制砂中2.3-3.0mm掺量", "机制砂粗3.1-3.7mm掺量", "机制砂细1.6-2.2mm掺量", "机制砂0-4.75mm掺量", "机制砂0-9mm掺量"));
//        replaceFeature(selectFeature, "砂细度", Arrays.asList("河砂粗3.1-3.7mm细度", "河砂中2.3-3.0mm细度", "河砂细1.6-2.2mm细度", "机制砂中2.3-3.0mm细度", "机制砂粗3.1-3.7mm细度", "机制砂细1.6-2.2mm细度", "机制砂0-4.75mm细度", "机制砂0-9mm细度"));
//        replaceFeature(selectFeature, "砂堆积密度", Arrays.asList("河砂粗3.1-3.7mm堆积密度(kg/m³)", "河砂中2.3-3.0mm堆积密度(kg/m³)", "河砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂中2.3-3.0mm堆积密度(kg/m³)", "机制砂粗3.1-3.7mm堆积密度(kg/m³)", "机制砂细1.6-2.2mm堆积密度(kg/m³)", "机制砂0-4.75mm堆积密度(kg/m³)", "机制砂0-9mm堆积密度(kg/m³)"));
//        replaceFeature(selectFeature, "砂紧密密度", Arrays.asList("河砂粗3.1-3.7mm紧密密度(kg/m³)", "河砂中2.3-3.0mm紧密密度(kg/m³)", "河砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂中2.3-3.0mm紧密密度(kg/m³)", "机制砂粗3.1-3.7mm紧密密度(kg/m³)", "机制砂细1.6-2.2mm紧密密度(kg/m³)", "机制砂0-4.75mm紧密密度(kg/m³)", "机制砂0-9mm紧密密度(kg/m³)"));
//        replaceFeature(selectFeature, "砂表观密度", Arrays.asList("河砂粗3.1-3.7mm表观密度(kg/m³)", "河砂中2.3-3.0mm表观密度(kg/m³)", "河砂细1.6-2.2mm表观密度(kg/m³)", "机制砂中2.3-3.0mm表观密度(kg/m³)", "机制砂粗3.1-3.7mm表观密度(kg/m³)", "机制砂细1.6-2.2mm表观密度(kg/m³)", "机制砂0-4.75mm表观密度(kg/m³)", "机制砂0-9mm表观密度(kg/m³)"));
//
//        // 递归检查 pythonBelowNamicDTO 中是否包含 NaN
//        if (containsNaN(pythonUpperBelowDTO)) {
//            return AjaxResult.error("数据错误，包含 NaN");
//        }
//
//        // 调用接口
//        AjaxResult ajaxResult = null;
//        try {
//            ajaxResult = fileClient.upperBelow(pythonUpperBelowDTO);
//            // 处理返回结果，去除 NaN
//            cleanNaNValues(ajaxResult);
//
//            return ajaxResult;
//        } catch (Exception e) {
//            log.error("/upper/below/second算法报错:{}",e.getMessage());
//            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
//        }
//
//
//    }




    /**
     * 性能预测模块
     *
     * @return
     */

    @PostMapping("predictPerformance")
    public AjaxResult predictPerformance(@RequestBody PredictPerformanceDTO pythonUpperBelowDTO) {
        // 打印请求体的 type 值
        System.out.println("Received type: " + pythonUpperBelowDTO.getType());

        // 根据 type 设置路径
        String pklPath = "";
        String excelPath = "";
        // 根据 type 设置路径
        switch (pythonUpperBelowDTO.getType()) {
            case 1:
                pklPath = filePythonPklExcel + "best_xgb_model-525水泥-3天抗压强度-0.78-0.703.pkl";
                excelPath = filePythonPklExcel + "3天抗压强度-测试集结果prediction_and_actual.xlsx";
                break;
            case 2:
                pklPath = filePythonPklExcel + "best_xgb_model-525水泥-7天抗压强度-0.796-0.727.pkl";
                excelPath = filePythonPklExcel + "7天抗压强度-测试集结果prediction_and_actual.xlsx";
                break;
            case 3:
                pklPath = filePythonPklExcel + "best_xgb_model-525水泥-28天抗压强度-0.91-0.872.pkl";
                excelPath = filePythonPklExcel + "28天抗压强度-测试集结果prediction_and_actual.xlsx";
                break;
            case 4:
                pklPath = filePythonPklExcel + "best_xgb_model-525水泥-坍落度-0.973-0.962.pkl";
                excelPath = filePythonPklExcel + "坍落度-测试集结果prediction_and_actual.xlsx";
                break;
            case 5:
                // 如果是type为5，直接使用传入的路径
                pklPath = pythonUpperBelowDTO.getModelPath();
                excelPath = pythonUpperBelowDTO.getExcelFilePath();

                break;
            default:
                // 如果type不是1-5中的有效值，返回错误提示
                return new AjaxResult().put("error", "请输入正确的type字段!").put("code", "500");
        }

        // 设置模型路径和Excel文件路径
        pythonUpperBelowDTO.setModelPath(pklPath);
        pythonUpperBelowDTO.setExcelFilePath(excelPath);

        // 调用文件客户端进行性能预测
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.predictPerformance(pythonUpperBelowDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("predictPerformance算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);

        }


    }


    /**
     * 性能预测模块
     *
     * @return
     */

    @PostMapping("/predictPerformance/V2")
    public AjaxResult predictPerformanceV2(@RequestBody PredictPerformanceDTO pythonUpperBelowDTO) {
        // 打印请求体的 type 值
        System.out.println("Received type: " + pythonUpperBelowDTO.getType());

        // 根据 type 设置路径
        String pklPath = "";
        String excelPath = "";
        // 根据 type 设置路径
        switch (pythonUpperBelowDTO.getType()) {
            case 1:
                pklPath = filePythonPklExcel + "3predictPerformance天抗压强度.pkl";
                excelPath = filePythonPklExcel + "3predictPerformance天抗压强度-测试集结果prediction_and_actual.xlsx";
                break;
            case 2:
                pklPath = filePythonPklExcel + "7predictPerformance天抗压强度.pkl";
                excelPath = filePythonPklExcel + "7predictPerformance天抗压强度-测试集结果prediction_and_actual.xlsx";
                break;
            case 3:
                pklPath = filePythonPklExcel + "28predictPerformance天抗压强度.pkl";
                excelPath = filePythonPklExcel + "28predictPerformance天抗压强度-测试集结果prediction_and_actual.xlsx";
                break;
            case 4:
                pklPath = filePythonPklExcel + "predictPerformance坍落度.pkl";
                excelPath = filePythonPklExcel + "predictPerformance坍落度-测试集结果prediction_and_actual.xlsx";
                break;
            case 5:
                // 如果是type为5，直接使用传入的路径
                pklPath = pythonUpperBelowDTO.getModelPath();
                excelPath = pythonUpperBelowDTO.getExcelFilePath();

                break;
            default:
                // 如果type不是1-5中的有效值，返回错误提示
                return new AjaxResult().put("error", "请输入正确的type字段!").put("code", "500");
        }

        // 设置模型路径和Excel文件路径
        pythonUpperBelowDTO.setModelPath(pklPath);
        pythonUpperBelowDTO.setExcelFilePath(excelPath);

        // 调用文件客户端进行性能预测
        AjaxResult ajaxResult = null;
        try {
            ajaxResult = fileClient.predictPerformanceV2(pythonUpperBelowDTO);
            return ajaxResult;
        } catch (Exception e) {
            log.error("算法报错",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }


    }


    /**
     * 配比设计模块
     */


//    @PostMapping("/proportion/design")
//    public AjaxResult testProportion(@RequestBody ProportionDesignDTO dto) {
//        try {
//            AjaxResult result = fileClient.proportionDesign(dto);
//
//            ObjectMapper objectMapper = new ObjectMapper();
//
//            objectMapper.readTree(result)
//            return result;
//        } catch (Exception e) {
//            e.printStackTrace();  // 👈 打印异常信息
//            return AjaxResult.error("调用Python接口失败: " + e.getMessage());
//        }
//    }

//    @PostMapping("/proportion/design")
//    public ProportionDesignResultVO proportionDesign(@RequestBody ProportionDesignDTO proportionDesignDTO) {
//        ProportionDesignResult result = fileClient.proportionDesign(proportionDesignDTO);
//        ProportionDesignResultVO resultVO = new ProportionDesignResultVO();
//
//        if (result != null) {
//            resultVO.setHvPlotPath(result.getHvPlotPath());
//            resultVO.setParetoPath(result.getParetoPath());
//
//            String excelPath = result.getExcelPath();
//            if (excelPath != null && !excelPath.isEmpty()) {
//                try {
//                    List<Map<String, Object>> excelContent = ExcelUtils.readExcel(excelPath);
//                    resultVO.setExcelContent(excelContent);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    // 可选：设置一个字段记录错误，或记录日志
//                }
//            }
//        }
//
//        return resultVO;
//    }


//   @PostMapping("/proportion/design")
//    public Result<ProportionDesignResultVO> proportionDesign(@RequestBody ProportionDesignDTO proportionDesignDTO) {
//
//
//       Map<String, Double> pricesTon = proportionDesignDTO.getPricesTon();
//       Double aDouble1 = pricesTon.get("1");
//       Double aDouble2 = pricesTon.get("2");
//       Double aDouble3 = pricesTon.get("3");
//       Double aDouble4 = pricesTon.get("4");
//       Double aDouble5 = pricesTon.get("5");
//       Double aDouble6 = pricesTon.get("6");
//       Double aDouble7 = pricesTon.get("7");
//       Double aDouble8 = pricesTon.get("8");
//
//
//
//
//
//
//
//
//
//
//
//
//       ProportionDesignResult result = fileClient.proportionDesign(proportionDesignDTO);
//        ProportionDesignResultVO resultVO = new ProportionDesignResultVO();
//
//        if (result != null) {
//            resultVO.setHvPlotPath(result.getHvPlotPath());
//            resultVO.setParetoPath(result.getParetoPath());
//            resultVO.setExcelPath(result.getExcelPath());
//            String excelPath = result.getExcelPath();
//            if (excelPath != null && !excelPath.isEmpty()) {
//                try {
//                    List<Map<String, Object>> excelContent = ExcelUtils.readExcel(excelPath);
//                    resultVO.setExcelContent(excelContent);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    return Result.error("读取Excel失败");
//                }
//            }
//        }
//
//        return Result.success(resultVO);
//    }
//





/*pricesTon
variableRanges
combinedConstraints*/
//    @PostMapping("/proportion/design")
//    public Result<ProportionDesignResultVO> proportionDesign(@RequestBody ProportionDesignDTO proportionDesignDTO) {
//
//        Map<String, Double> pricesTon = proportionDesignDTO.getPricesTon();
//        Map<String, List<Integer>> variableRanges = proportionDesignDTO.getVariableRanges();
//        Map<String, List<Double>> combinedConstraints = proportionDesignDTO.getCombinedConstraints();
//        System.out.println("pricesTon"+pricesTon);
//        System.out.println("variableRanges"+variableRanges);
//        System.out.println("combinedConstraints"+combinedConstraints);
//
//        // 原始可能是 Integer 类型的 key，强制转为 String
//        Map<?, Double> originalPricesTon = proportionDesignDTO.getPricesTon();
//
//        // 映射关系：数字 key → 材料名
//        Map<String, String> keyMapping = new HashMap<>();
//        keyMapping.put("1", "水");
//        keyMapping.put("2", "水泥PⅡ 52.5R");
//        keyMapping.put("3", "机制砂");
//        keyMapping.put("4", "碎石_5~25mm");
//        keyMapping.put("5", "矿渣粉_S95");
//        keyMapping.put("6", "粉煤灰_Ⅱ级");
//        keyMapping.put("7", "减水剂");
//        keyMapping.put("8", "增效剂_HX-T608");
//
//        // 转换 key
//        Map<String, Double> replacedPricesTon = new HashMap<>();
//        for (Map.Entry<?, Double> entry : originalPricesTon.entrySet()) {
//            String originalKey = entry.getKey().toString(); // 不管是 Integer 还是 String 都变成 String
//            String replacedKey = keyMapping.getOrDefault(originalKey, originalKey);
//            replacedPricesTon.put(replacedKey, entry.getValue());
//        }
//
//        // 替换回 DTO
//        proportionDesignDTO.setPricesTon(replacedPricesTon);
//        System.out.println("replacedPricesTon: " + replacedPricesTon);
///*-----------------------------------------------------------------------------------------------------*/
//// 处理 variableRanges，key 也可能是 Integer 类型
//        Map<?, List<Integer>> originalVariableRanges = proportionDesignDTO.getVariableRanges();
//
//// 映射关系：数字 key → 材料名
//        Map<String, String> keyMapping1 = new HashMap<>();
//        keyMapping1.put("1", "水");
//        keyMapping1.put("2", "水泥PⅡ 52.5R");
//        keyMapping1.put("3", "机制砂");
//        keyMapping1.put("4", "碎石_5~25mm");
//        keyMapping1.put("5", "矿渣粉_S95");
//        keyMapping1.put("6", "粉煤灰_Ⅱ级");
//        keyMapping1.put("7", "减水剂");
//        keyMapping1.put("8", "增效剂_HX-T608");
//
//// 转换 key
//        Map<String, List<Integer>> replacedVariableRanges = new HashMap<>();
//        for (Map.Entry<?, List<Integer>> entry : originalVariableRanges.entrySet()) {
//            String originalKey = entry.getKey().toString(); // 把 key 变成 String
//            String replacedKey = keyMapping1.getOrDefault(originalKey, originalKey);
//            replacedVariableRanges.put(replacedKey, entry.getValue());
//        }
//
//// 替换回 DTO
//        proportionDesignDTO.setVariableRanges(replacedVariableRanges);
//
//        System.out.println("replacedvariableRanges: " + replacedVariableRanges);
///*-------------------------------------------------------------------------*/
//
//// 处理 combinedConstraints，key 也可能是 Integer 类型
//        Map<?, List<Double>> originalCombinedConstraints = proportionDesignDTO.getCombinedConstraints();
//
//// 映射关系：数字 key → 约束条件名
//        Map<String, String> keyMapping2 = new HashMap<>();
//        keyMapping2.put("1", "胶凝材料");
//        keyMapping2.put("2", "水胶比");
//        keyMapping2.put("3", "水灰比");
//        keyMapping2.put("4", "砂胶比");
//        keyMapping2.put("5", "砂率");
//        keyMapping2.put("6", "单方材料总质量");
//        keyMapping2.put("7", "28天抗压强度");
//        keyMapping2.put("8", "坍落度");
//
//// 转换 key
//        Map<String, List<Double>> replacedCombinedConstraints = new HashMap<>();
//        for (Map.Entry<?, List<Double>> entry : originalCombinedConstraints.entrySet()) {
//            String originalKey = entry.getKey().toString(); // 把 key 转成 String
//            String replacedKey = keyMapping2.getOrDefault(originalKey, originalKey);
//            replacedCombinedConstraints.put(replacedKey, entry.getValue());
//        }
//
//// 替换回 DTO
//        proportionDesignDTO.setCombinedConstraints(replacedCombinedConstraints);
//
//        System.out.println("replacedCombinedConstraints: " + replacedCombinedConstraints);
//
//
//
//
//        // 后续远程调用逻辑保持不变
//        ProportionDesignResult result = fileClient.proportionDesign(proportionDesignDTO);
//        ProportionDesignResultVO resultVO = new ProportionDesignResultVO();
//
//        if (result != null) {
//            resultVO.setHvPlotPath(result.getHvPlotPath());
//            resultVO.setParetoPath(result.getParetoPath());
//            resultVO.setExcelPath(result.getExcelPath());
//
//            String excelPath = result.getExcelPath();
//            if (excelPath != null && !excelPath.isEmpty()) {
//                try {
//                    List<Map<String, Object>> excelContent = ExcelUtils.readExcel(excelPath);
//                    resultVO.setExcelContent(excelContent);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                    return Result.error("读取Excel失败");
//                }
//            }
//        }
//
//        return Result.success(resultVO);
//
//
//    }
    @PostMapping("/proportion/design")
    public Result<ProportionDesignResultVO> proportionDesign(@RequestBody ProportionDesignDTO proportionDesignDTO) {
        // 原始数据
        Map<?, Double> originalPricesTon = proportionDesignDTO.getPricesTon();
        Map<?, List<Integer>> originalVariableRanges = proportionDesignDTO.getVariableRanges();
        Map<?, List<Double>> originalCombinedConstraints = proportionDesignDTO.getCombinedConstraints();
        System.out.println("pricesTon" + originalPricesTon);
        System.out.println("variableRanges" + originalVariableRanges);
        System.out.println("combinedConstraints" + originalCombinedConstraints);


        // 映射关系 - 材料价格和掺量
        Map<String, String> materialMapping = new HashMap<>();
        materialMapping.put("1", "水");
        materialMapping.put("2", "水泥PⅡ 52.5R");
        materialMapping.put("3", "机制砂");
        materialMapping.put("4", "碎石_5~25mm");
        materialMapping.put("5", "矿渣粉_S95");
        materialMapping.put("6", "粉煤灰_Ⅱ级");
        materialMapping.put("7", "减水剂");
        materialMapping.put("8", "增效剂_HX-T608");

        // 映射关系 - 配比组合约束
        Map<String, String> constraintMapping = new HashMap<>();
        constraintMapping.put("1", "胶凝材料");
        constraintMapping.put("2", "水胶比");
        constraintMapping.put("3", "水灰比");
        constraintMapping.put("4", "砂胶比");
        constraintMapping.put("5", "砂率");
        constraintMapping.put("6", "单方材料总质量");
        constraintMapping.put("7", "28天抗压强度");
        constraintMapping.put("8", "坍落度");

        // 替换并排序
        Map<String, Double> replacedPricesTon = sortAndReplaceKeys(originalPricesTon, materialMapping);
        Map<String, List<Integer>> replacedVariableRanges = sortAndReplaceKeys(originalVariableRanges, materialMapping);
        Map<String, List<Double>> replacedCombinedConstraints = sortAndReplaceKeys(originalCombinedConstraints, constraintMapping);

        // 替换回 DTO
        proportionDesignDTO.setPricesTon(replacedPricesTon);
        proportionDesignDTO.setVariableRanges(replacedVariableRanges);
        proportionDesignDTO.setCombinedConstraints(replacedCombinedConstraints);

        System.out.println("replacedPricesTon: " + replacedPricesTon);
        System.out.println("replacedVariableRanges: " + replacedVariableRanges);
        System.out.println("replacedCombinedConstraints: " + replacedCombinedConstraints);

        // 后续远程调用逻辑
        ProportionDesignResult result = null;
        try {
            result = fileClient.proportionDesign(proportionDesignDTO);
            ProportionDesignResultVO resultVO = new ProportionDesignResultVO();

            if (result != null) {
                resultVO.setHvPlotPath(result.getHvPlotPath());
                resultVO.setParetoPath(result.getParetoPath());
                resultVO.setExcelPath(result.getExcelPath());

                String excelPath = result.getExcelPath();
                if (excelPath != null && !excelPath.isEmpty()) {
                    try {
                        List<Map<String, Object>> excelContent = ExcelUtils.readExcel(excelPath);
                        resultVO.setExcelContent(excelContent);
                    } catch (IOException e) {
                        e.printStackTrace();
                        return Result.error("读取Excel失败");
                    }
                }
            }

            return Result.success(resultVO);
        } catch (Exception e) {
            log.error("/proportion/design算法报错：{}",e.getMessage());
            return Result.error("算法未预测出结果,请重选新数据重试！");
        }

    }

    /**
     * 通用方法：排序+替换key
     */
    private <T> Map<String, T> sortAndReplaceKeys(Map<?, T> originalMap, Map<String, String> keyMapping) {
        Map<String, T> sortedMap = new LinkedHashMap<>();
        originalMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey((a, b) -> Integer.compare(Integer.parseInt(a.toString()), Integer.parseInt(b.toString()))))
                .forEach(entry -> {
                    String originalKey = entry.getKey().toString();
                    String replacedKey = keyMapping.getOrDefault(originalKey, originalKey);
                    sortedMap.put(replacedKey, entry.getValue());
                });
        return sortedMap;
    }


    @PostMapping("/proportion/design/text")
    public Result<ProportionDesignResultVO> proportionDesigntext(@RequestBody ProportionDesignV2DTO proportionDesignDTO) {

        System.out.println("哈哈哈" + proportionDesignDTO);
        ProportionDesignResult result = null;
        try {
            result = fileClient.proportionDesignV2(proportionDesignDTO);
            ProportionDesignResultVO resultVO = new ProportionDesignResultVO();
            resultVO.setHvPlotPath(result.getHvPlotPath());
            resultVO.setParetoPath(result.getParetoPath());
            resultVO.setExcelPath(result.getExcelPath());

            resultVO.setExcelContent(Collections.emptyList());  // or null

            return Result.success(resultVO);
        } catch (Exception e) {
            log.error("/proportion/design/text算法报错:{}",e);
            return Result.error("算法未预测出结果,请重选新数据重试！");

        }

    }


    @PostMapping("/proportion/design/V2")
    public Result<ProportionDesignResultVO> proportionDesignV2(@RequestBody ProportionDesignV2DTO proportionDesignDTO) {


        Map<String, String> numberToName = new HashMap<>();
        numberToName.put("1", "水用量");
        numberToName.put("2", "水泥用量");
        numberToName.put("3", "矿粉用量");
        numberToName.put("4", "粉煤灰用量");
        numberToName.put("5", "砂用量");
        numberToName.put("6", "石用量");
        numberToName.put("7", "减水剂用量");
        numberToName.put("8", "增效剂用量");

        Map<String, String> numberToCombined = new HashMap<>();
        numberToCombined.put("1", "胶凝材料");
        numberToCombined.put("2", "水胶比");
        numberToCombined.put("3", "水灰比");
        numberToCombined.put("4", "砂胶比");
        numberToCombined.put("5", "砂率");
        numberToCombined.put("6", "单方材料总质量");

        Map<String, String> numberToObjective = new HashMap<>();
        numberToObjective.put("1", "28天抗压强度");
        numberToObjective.put("2", "坍落度");
        numberToObjective.put("3", "3天抗压强度");
        numberToObjective.put("4", "7天抗压强度");
        numberToObjective.put("5", "成本");

        Map<String, String> numberToIndicatorParam = new HashMap<>();
        numberToIndicatorParam.put("1", "水泥种类");
        numberToIndicatorParam.put("2", "水泥细度");
        numberToIndicatorParam.put("3", "水泥28天强度");
        numberToIndicatorParam.put("4", "矿粉细度");
        numberToIndicatorParam.put("5", "矿粉活性指数");
        numberToIndicatorParam.put("6", "粉煤灰细度");
        numberToIndicatorParam.put("7", "粉煤灰活性指数");
        numberToIndicatorParam.put("8", "砂细度");
        numberToIndicatorParam.put("9", "砂石粉含量");
        numberToIndicatorParam.put("10", "石含泥量");
        numberToIndicatorParam.put("11", "石压碎指标");
        numberToIndicatorParam.put("12", "减水剂含固量");
        numberToIndicatorParam.put("13", "减水剂流动度");


        // 替换数字键为中文键，并排序（数字顺序）
        proportionDesignDTO.setPricesTon(replaceKeysAndSort(proportionDesignDTO.getPricesTon(), numberToName));
        proportionDesignDTO.setVariableRanges(replaceKeysAndSort(proportionDesignDTO.getVariableRanges(), numberToName));
        proportionDesignDTO.setCombinedConstraints(replaceKeysAndSort(proportionDesignDTO.getCombinedConstraints(), numberToCombined));
        proportionDesignDTO.setObjectiveConstraints(replaceKeysAndSort(proportionDesignDTO.getObjectiveConstraints(), numberToObjective));
        proportionDesignDTO.setIndicatorParams(replaceKeysAndSort(proportionDesignDTO.getIndicatorParams(), numberToIndicatorParam));

        // 调试日志
        System.out.println("调用Python服务前参数: " + proportionDesignDTO);

        ProportionDesignResult result;
        try {
            System.out.println("请求参数JSON: " + new ObjectMapper().writeValueAsString(proportionDesignDTO));
            result = fileClient.proportionDesignV2(proportionDesignDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("算法未预测出结果,请重选新数据重试！" + e.getMessage());
        }

        if (result == null) {
            return Result.error("Python模型返回为空");
        }

        ProportionDesignResultVO resultVO = convertToVO(result);
        resultVO.setHvPlotPath(result.getHvPlotPath());
        resultVO.setParetoPath(result.getParetoPath());
        resultVO.setExcelPath(result.getExcelPath());

        if (result.getExcelPath() != null && !result.getExcelPath().isEmpty()) {
            try {
                List<Map<String, Object>> excelContent = ExcelUtils.readExcelV2(result.getExcelPath());
                resultVO.setExcelContent(excelContent == null ? Collections.emptyList() : excelContent);
            } catch (IOException e) {
                e.printStackTrace();
                resultVO.setExcelContent(Collections.emptyList());
            }
        } else {
            resultVO.setExcelContent(Collections.emptyList());
        }

        return Result.success(resultVO);
    }





    @PostMapping("/proportion/design/V3")
    public Result<ProportionDesignResultVO> proportionDesignV3(@RequestBody ProportionDesignV2DTO proportionDesignDTO) {


        Map<String, String> numberToName = new HashMap<>();
        numberToName.put("1", "水用量");
        numberToName.put("2", "水泥用量");
        numberToName.put("3", "矿粉用量");
        numberToName.put("4", "粉煤灰用量");
        numberToName.put("5", "砂用量");
        numberToName.put("6", "石用量");
        numberToName.put("7", "减水剂用量");
        numberToName.put("8", "增效剂用量");

        Map<String, String> numberToCombined = new HashMap<>();
        numberToCombined.put("1", "胶凝材料");
        numberToCombined.put("2", "水胶比");
        numberToCombined.put("3", "水灰比");
        numberToCombined.put("4", "砂胶比");
        numberToCombined.put("5", "砂率");
        numberToCombined.put("6", "单方材料总质量");

        Map<String, String> numberToObjective = new HashMap<>();
        numberToObjective.put("1", "28天抗压强度");
        numberToObjective.put("2", "坍落度");
        numberToObjective.put("3", "3天抗压强度");
        numberToObjective.put("4", "7天抗压强度");
        numberToObjective.put("5", "成本");

        Map<String, String> numberToIndicatorParam = new HashMap<>();
        numberToIndicatorParam.put("1", "水泥种类");
        numberToIndicatorParam.put("2", "水泥细度");
        numberToIndicatorParam.put("3", "水泥28天强度");
        numberToIndicatorParam.put("4", "矿粉细度");
        numberToIndicatorParam.put("5", "矿粉活性指数");
        numberToIndicatorParam.put("6", "粉煤灰细度");
        numberToIndicatorParam.put("7", "粉煤灰活性指数");
        numberToIndicatorParam.put("8", "砂细度");
        numberToIndicatorParam.put("9", "砂石粉含量");
        numberToIndicatorParam.put("10", "石含泥量");
        numberToIndicatorParam.put("11", "石压碎指标");
        numberToIndicatorParam.put("12", "减水剂含固量");
        numberToIndicatorParam.put("13", "减水剂流动度");


        // 替换数字键为中文键，并排序（数字顺序）
        proportionDesignDTO.setPricesTon(replaceKeysAndSortV3(proportionDesignDTO.getPricesTon(), numberToName));
        proportionDesignDTO.setVariableRanges(replaceKeysAndSortV3(proportionDesignDTO.getVariableRanges(), numberToName));
        proportionDesignDTO.setCombinedConstraints(replaceKeysAndSortV3(proportionDesignDTO.getCombinedConstraints(), numberToCombined));
        proportionDesignDTO.setObjectiveConstraints(replaceKeysAndSortV3(proportionDesignDTO.getObjectiveConstraints(), numberToObjective));
        proportionDesignDTO.setIndicatorParams(replaceKeysAndSortV3(proportionDesignDTO.getIndicatorParams(), numberToIndicatorParam));

        // 调试日志
        System.out.println("调用Python服务前参数: " + proportionDesignDTO);

        ProportionDesignResult result;
        try {
            System.out.println("请求参数JSON: " + new ObjectMapper().writeValueAsString(proportionDesignDTO));
            result = fileClient.proportionDesignV3(proportionDesignDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("算法未预测出结果,请重选新数据重试！" + e.getMessage());
        }

        if (result == null) {
            return Result.error("Python模型返回为空");
        }

        ProportionDesignResultVO resultVO = convertToVO(result);
        resultVO.setHvPlotPath(result.getHvPlotPath());
        resultVO.setParetoPath(result.getParetoPath());
        resultVO.setExcelPath(result.getExcelPath());

        if (result.getExcelPath() != null && !result.getExcelPath().isEmpty()) {
            try {
                List<Map<String, Object>> excelContent = ExcelUtils.readExcelV2(result.getExcelPath());
                resultVO.setExcelContent(excelContent == null ? Collections.emptyList() : excelContent);
            } catch (IOException e) {
                e.printStackTrace();
                resultVO.setExcelContent(Collections.emptyList());
            }
        } else {
            resultVO.setExcelContent(Collections.emptyList());
        }

        return Result.success(resultVO);
    }


    private <T> Map<String, T> replaceKeysAndSortV3(Map<?, T> originalMap, Map<String, String> keyMapping) {
        if (originalMap == null || originalMap.isEmpty()) {
            return Collections.emptyMap();
        }

        Map<String, T> sortedMap = new LinkedHashMap<>();
        List<String> sortedKeys = new ArrayList<>();

        for (Object keyObj : originalMap.keySet()) {
            sortedKeys.add(keyObj.toString());
        }

        Collections.sort(sortedKeys, (o1, o2) -> {
            try {
                return Integer.compare(Integer.parseInt(o1), Integer.parseInt(o2));
            } catch (NumberFormatException e) {
                return o1.compareTo(o2);
            }
        });

        for (String key : sortedKeys) {
            String replacedKey = keyMapping.getOrDefault(key, key);
            sortedMap.put(replacedKey, originalMap.get(key));
        }

        return sortedMap;
    }


    /**
     * 知识图谱
     */

    @PostMapping("/knowledge/photo")
    public AjaxResult knowledgePhoto(@RequestBody KnowledgePhotoDTO knowledgePhotoDTO) {
        //   final String REDIS_KEY = "knowledge:photo:data";

        // 1. 查询 Redis 缓存
        Object cachedData = redisTemplate.opsForValue().get(REDIS_KEY);
        if (cachedData != null) {
            return AjaxResult.success(cachedData);
        }

        try {
            // 2. 查询数据库数据
            List<SysMechanicalPerformance> list1 = sysMechanicalPerformanceService.list();
            List<SysSlump> list2 = sysSlumpService.list();

            List<MechanicalPerformanceVO> voList1 = new ArrayList<>();
            for (SysMechanicalPerformance sys : list1) {
                MechanicalPerformanceVO vo = new MechanicalPerformanceVO();
                BeanUtils.copyProperties(sys, vo);
                if (sys.getProductionDate() != null) {
                    vo.setProductionDate(java.sql.Timestamp.valueOf(sys.getProductionDate()));
                }
                voList1.add(vo);
            }

            List<SlumpVO> voList2 = new ArrayList<>();
            for (SysSlump entity : list2) {
                SlumpVO vo = new SlumpVO();
                BeanUtils.copyProperties(entity, vo);
                if (entity.getProductionDate() != null) {
                    vo.setProductionDate(Date.from(entity.getProductionDate().atZone(ZoneId.systemDefault()).toInstant()));
                }
                voList2.add(vo);
            }

            // 3. 构造 Excel 文件路径
            UUID uuid = UUID.randomUUID();
            int hash = Math.abs(uuid.hashCode());
            String fileName = System.currentTimeMillis() + "_" + String.format("%07d", hash % 10000000) + ".xlsx";
            String filePath = mechanicalPerformanceExcelPath + fileName;

            // 4. 写入 Excel 文件
            try (Workbook workbook = new XSSFWorkbook()) {
                ExcelUtil<MechanicalPerformanceVO> util1 = new ExcelUtil<>(MechanicalPerformanceVO.class);
                ExcelUtil<SlumpVO> util2 = new ExcelUtil<>(SlumpVO.class);
                util1.writeToWorkbookSheet(workbook, "力学性能", voList1);
                util2.writeToWorkbookSheet(workbook, "坍落度", voList2);
                try (FileOutputStream out = new FileOutputStream(filePath)) {
                    workbook.write(out);
                }
            } catch (IOException e) {
                log.error("写入Excel失败：", e);
                return AjaxResult.error("算法未预测出结果，请重选数据重试！", e);
            }

            // 5. 调用算法接口
            knowledgePhotoDTO.setExcelUrl(filePath);
            KnowledgePhotoVO knowledgePhotoVO = fileClient.knowledgePhoto(knowledgePhotoDTO);

            String excelPath1 = knowledgePhotoVO.getExcelPath1();
            String excelPath2 = knowledgePhotoVO.getExcelPath2();

            // 6. 解析 Excel 并合并列数据
            List<List<List<List<String>>>> lists = parseExcelColumns(excelPath1, excelPath2);
            List<List<String>> compressive = mergeSheetsColumns(lists.get(0));
            List<List<String>> slump = mergeSheetsColumns(lists.get(1));

            Map<String, Object> data = new HashMap<>();
            data.put("compressive", compressive);
            data.put("slump", slump);

            // 7. 写入 Redis 缓存
            redisTemplate.opsForValue().set(REDIS_KEY, data, Duration.ofHours(24));


            return AjaxResult.success(data);
        } catch (Exception e) {
            log.error("/modelPkl 算法报错: {}", e.getMessage(), e);
            return AjaxResult.error("算法未预测出结果，请重选数据重试！", e);
        }
    }

/*    public AjaxResult knowledgePhoto(@RequestBody KnowledgePhotoDTO knowledgePhotoDTO) {
        try {
            // 1. 查询数据
            List<SysMechanicalPerformance> list1 = sysMechanicalPerformanceService.list();
            List<SysSlump> list2 = sysSlumpService.list();

            List<MechanicalPerformanceVO> voList1 = new ArrayList<>();
            for (SysMechanicalPerformance sys : list1) {
                MechanicalPerformanceVO vo = new MechanicalPerformanceVO();
                BeanUtils.copyProperties(sys, vo);
                if (sys.getProductionDate() != null) {
                    vo.setProductionDate(java.sql.Timestamp.valueOf(sys.getProductionDate()));
                }
                voList1.add(vo);
            }

            List<SlumpVO> voList2 = new ArrayList<>();
            for (SysSlump entity : list2) {
                SlumpVO vo = new SlumpVO();
                BeanUtils.copyProperties(entity, vo);
                if (entity.getProductionDate() != null) {
                    vo.setProductionDate(Date.from(entity.getProductionDate().atZone(ZoneId.systemDefault()).toInstant()));
                }
                voList2.add(vo);
            }

            // 2. 构造文件路径
            UUID uuid = UUID.randomUUID();
            int hash = Math.abs(uuid.hashCode());
            int sevenDigitNumber = hash % 10000000;
            String number = String.format("%07d", sevenDigitNumber);
            String fileName = System.currentTimeMillis() + "_" + number + ".xlsx";
            String filePath = mechanicalPerformanceExcelPath + fileName;

            // 3. 创建 workbook，并将两个 sheet 写入
            try (Workbook workbook = new XSSFWorkbook()) {
                ExcelUtil<MechanicalPerformanceVO> util1 = new ExcelUtil<>(MechanicalPerformanceVO.class);
                ExcelUtil<SlumpVO> util2 = new ExcelUtil<>(SlumpVO.class);
                util1.writeToWorkbookSheet(workbook, "力学性能", voList1);
                util2.writeToWorkbookSheet(workbook, "坍落度", voList2);
                try (FileOutputStream out = new FileOutputStream(filePath)) {
                    workbook.write(out);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
            }

            knowledgePhotoDTO.setExcelUrl(filePath);
            KnowledgePhotoVO knowledgePhotoVO = fileClient.knowledgePhoto(knowledgePhotoDTO);

            String excelPath1 = knowledgePhotoVO.getExcelPath1();  // 压缩性能Excel路径
            String excelPath2 = knowledgePhotoVO.getExcelPath2();  // 坍落度Excel路径

            // 解析两个Excel文件，每个文件可能有多个sheet，合并所有sheet的列数据
            List<List<List<List<String>>>> lists = parseExcelColumns(excelPath1, excelPath2);

            // 合并所有sheet列数据，得到每个Excel的单层列列表
            List<List<String>> compressive = mergeSheetsColumns(lists.get(0));
            List<List<String>> slump = mergeSheetsColumns(lists.get(1));

            Map<String, Object> data = new HashMap<>();
            data.put("compressive", compressive);
            data.put("slump", slump);
            //写入redis
            redisTemplate.opsForValue().set(REDIS_KEY, data);

            return AjaxResult.success(data);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("/modelPkl算法报错:{}",e.getMessage());
            return AjaxResult.error("算法未预测出结果,请重选新数据重试！",e);
        }
    }*/





    public List<List<List<List<String>>>> parseExcelColumns(String... excelPaths) throws IOException {
        List<List<List<List<String>>>> allExcelData = new ArrayList<>();

        for (String path : excelPaths) {
            try (FileInputStream fis = new FileInputStream(path);
                 Workbook workbook = WorkbookFactory.create(fis)) {

                List<List<List<String>>> oneExcelSheets = new ArrayList<>();

                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                    Sheet sheet = workbook.getSheetAt(i);
                    int maxCol = 0;
                    for (Row row : sheet) {
                        maxCol = Math.max(maxCol, row.getLastCellNum());
                    }

                    List<List<String>> columns = new ArrayList<>();
                    for (int col = 0; col < maxCol; col++) {
                        columns.add(new ArrayList<>());
                    }

                    for (Row row : sheet) {
                        for (int col = 0; col < maxCol; col++) {
                            Cell cell = row.getCell(col, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                            columns.get(col).add(getCellString(cell));
                        }
                    }

                    oneExcelSheets.add(columns);  // 每个 sheet 是一组列数据
                }

                allExcelData.add(oneExcelSheets);  // 每个 Excel 是多个 sheet
            }
        }

        return allExcelData;
    }

    /**
     * 合并多个sheet的列数据为一个列表
     * @param sheetsColumns 每个sheet的列数据集合
     * @return 合并后的列数据列表
     */
    private List<List<String>> mergeSheetsColumns(List<List<List<String>>> sheetsColumns) {
        List<List<String>> merged = new ArrayList<>();
        for (List<List<String>> sheetColumns : sheetsColumns) {
            merged.addAll(sheetColumns);
        }
        return merged;
    }

    private String getCellString(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cell.getDateCellValue());
                } else {
                    // 处理数值类型，避免科学计数法
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == (long) numericValue) {
                        return String.valueOf((long) numericValue);
                    } else {
                        return String.valueOf(numericValue);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                // 这里直接取公式字符串，或者你也可以计算公式值
                return cell.getCellFormula();
            case BLANK:
            default:
                return "";
        }
    }


/*666
    @PostMapping("/knowledge/photo")
    public AjaxResult knowledgePhoto(@RequestBody KnowledgePhotoDTO knowledgePhotoDTO) {

        try {

            // 1. 查询数据
            List<SysMechanicalPerformance> list1 = sysMechanicalPerformanceService.list();
            List<SysSlump> list2 = sysSlumpService.list();

            List<MechanicalPerformanceVO> voList1 = new ArrayList<>();
            for (SysMechanicalPerformance sys : list1) {
                MechanicalPerformanceVO vo = new MechanicalPerformanceVO();
                BeanUtils.copyProperties(sys, vo);
                if (sys.getProductionDate() != null) {
                    vo.setProductionDate(java.sql.Timestamp.valueOf(sys.getProductionDate()));
                }
                voList1.add(vo);
            }

            List<SlumpVO> voList2 = new ArrayList<>();
            for (SysSlump entity : list2) {
                SlumpVO vo = new SlumpVO();
                BeanUtils.copyProperties(entity, vo);
                if (entity.getProductionDate() != null) {
                    vo.setProductionDate(Date.from(entity.getProductionDate().atZone(ZoneId.systemDefault()).toInstant()));
                }
                voList2.add(vo);
            }

            // 2. 构造文件路径
            UUID uuid = UUID.randomUUID();
            int hash = Math.abs(uuid.hashCode());
            int sevenDigitNumber = hash % 10000000;
            String number = String.format("%07d", sevenDigitNumber);
            String fileName = System.currentTimeMillis() + "_" + number + ".xlsx";
            String filePath = mechanicalPerformanceExcelPath + fileName;

            // 3. 创建 workbook，并将两个 sheet 写入
            try (Workbook workbook = new XSSFWorkbook()) {
                ExcelUtil<MechanicalPerformanceVO> util1 = new ExcelUtil<>(MechanicalPerformanceVO.class);
                ExcelUtil<SlumpVO> util2 = new ExcelUtil<>(SlumpVO.class);
                util1.writeToWorkbookSheet(workbook, "力学性能", voList1);
                util2.writeToWorkbookSheet(workbook, "坍落度", voList2);
                try (FileOutputStream out = new FileOutputStream(filePath)) {
                    workbook.write(out);
                }
            } catch (IOException e) {
                e.printStackTrace();
                return AjaxResult.error("生成excel出错：" + e.getMessage());
            }

            knowledgePhotoDTO.setExcelUrl(filePath);
            KnowledgePhotoVO knowledgePhotoVO = fileClient.knowledgePhoto(knowledgePhotoDTO);


            String excelPath1 = knowledgePhotoVO.getExcelPath1();
            String excelPath2 = knowledgePhotoVO.getExcelPath2();

            // 解析两个Excel文件，每个文件两个sheet
            List<List<List<List<String>>>> lists = parseExcelColumns(excelPath1, excelPath2);
            Map<String, Object> data = new HashMap<>();
            data.put("compressive", lists.get(0)); // excelPath1内容
            data.put("slump", lists.get(1));       // excelPath2内容
            return AjaxResult.success(data);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("/knowledge/photo算法报错: " + e.getMessage());
        }
    }


    public List<List<List<List<String>>>> parseExcelColumns(String... excelPaths) throws IOException {
        List<List<List<List<String>>>> allExcelData = new ArrayList<>();

        for (String path : excelPaths) {
            try (FileInputStream fis = new FileInputStream(path);
                 Workbook workbook = WorkbookFactory.create(fis)) {

                List<List<List<String>>> oneExcelSheets = new ArrayList<>();

                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                    Sheet sheet = workbook.getSheetAt(i);
                    int maxCol = 0;
                    for (Row row : sheet) {
                        maxCol = Math.max(maxCol, row.getLastCellNum());
                    }

                    List<List<String>> columns = new ArrayList<>();
                    for (int col = 0; col < maxCol; col++) {
                        columns.add(new ArrayList<>());
                    }

                    for (Row row : sheet) {
                        for (int col = 0; col < maxCol; col++) {
                            Cell cell = row.getCell(col, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                            columns.get(col).add(getCellString(cell));
                        }
                    }

                    oneExcelSheets.add(columns);  // 每个 sheet 是一组列数据
                }

                allExcelData.add(oneExcelSheets);  // 每个 Excel 是多个 sheet
            }
        }

        return allExcelData;
    }


    private String getCellString(Cell cell) {
        if (cell == null) return "";
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(cell.getDateCellValue());
                } else {
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            case BLANK:
            default:
                return "";
        }
    }

*/


    /**
     * 工具方法：替换 Map 中的数字 key 为中文，并按数字顺序排序
     */
    private <T> Map<String, T> replaceKeysAndSort(Map<?, T> originalMap, Map<String, String> keyMapping) {
        Map<String, T> sortedMap = new LinkedHashMap<>();
        List<String> sortedKeys = new ArrayList<>();

        for (Object keyObj : originalMap.keySet()) {
            sortedKeys.add(keyObj.toString());
        }

        Collections.sort(sortedKeys, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return Integer.compare(Integer.parseInt(o1), Integer.parseInt(o2));
            }
        });

        for (String key : sortedKeys) {
            String replacedKey = keyMapping.containsKey(key) ? keyMapping.get(key) : key;
            sortedMap.put(replacedKey, originalMap.get(key));
        }

        return sortedMap;
    }


    private ProportionDesignResultVO convertToVO(ProportionDesignResult result) {
        ProportionDesignResultVO vo = new ProportionDesignResultVO();
        vo.setHvPlotPath(result.getHvPlotPath());
        vo.setParetoPath(result.getParetoPath());
        vo.setExcelPath(result.getExcelPath());
        return vo;
    }


    /**
     * 替换 selectFeature 中的指定特征
     */
    private void replaceFeature(List<String> selectFeature, String key, List<String> replacements) {
        if (selectFeature.contains(key)) {
            selectFeature.remove(key);
            selectFeature.addAll(replacements);
        }
    }

    /**
     * 递归检查对象是否包含 NaN
     */
    private boolean containsNaN(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj instanceof Double && ((Double) obj).isNaN()) {
            return true;
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).values().stream().anyMatch(this::containsNaN);
        }
        if (obj instanceof List) {
            return ((List<?>) obj).stream().anyMatch(this::containsNaN);
        }
        return false;
    }

    /**
     * 递归清除 NaN 值
     */
    private void cleanNaNValues(Object obj) {
        if (obj instanceof Map) {
            ((Map<?, ?>) obj).replaceAll((k, v) -> {
                if (v instanceof Double && ((Double) v).isNaN()) {
                    return null; // 或者替换为 0.0
                }
                cleanNaNValues(v);
                return v;
            });
        } else if (obj instanceof List) {
            ((List<?>) obj).replaceAll(item -> {
                if (item instanceof Double && ((Double) item).isNaN()) {
                    return null; // 或者替换为 0.0
                }
                cleanNaNValues(item);
                return item;
            });
        }
    }


}
